1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.cache;
16  
17  import static com.google.common.base.Preconditions.checkNotNull;
18  
19  import com.google.common.annotations.GwtCompatible;
20  import com.google.common.annotations.GwtIncompatible;
21  import com.google.common.collect.Maps;
22  import com.google.common.util.concurrent.Futures;
23  import com.google.common.util.concurrent.ListenableFuture;
24  
25  import java.util.Map;
26  import java.util.concurrent.atomic.AtomicInteger;
27  
28  import javax.annotation.Nullable;
29  
30  /**
31   * Utility {@link CacheLoader} implementations intended for use in testing.
32   *
33   * @author mike nonemacher
34   */
35  @GwtCompatible(emulated = true)
36  class TestingCacheLoaders {
37  
38    /**
39     * Returns a {@link CacheLoader} that implements a naive {@link CacheLoader#loadAll}, delegating
40     * {@link CacheLoader#load} calls to {@code loader}.
41     */
42    static <K, V> CacheLoader<K, V> bulkLoader(final CacheLoader<K, V> loader) {
43      checkNotNull(loader);
44      return new CacheLoader<K, V>() {
45        @Override
46        public V load(K key) throws Exception {
47          return loader.load(key);
48        }
49  
50        @Override
51        public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
52          Map<K, V> result = Maps.newHashMap(); // allow nulls
53          for (K key : keys) {
54            result.put(key, load(key));
55          }
56          return result;
57        }
58      };
59    }
60  
61    /**
62     * Returns a {@link CacheLoader} that returns the given {@code constant} for every request.
63     */
64    static <K, V> ConstantLoader<K, V> constantLoader(@Nullable V constant) {
65      return new ConstantLoader<K, V>(constant);
66    }
67  
68    /**
69     * Returns a {@link CacheLoader} that returns the given {@code constant} for every request.
70     */
71    static IncrementingLoader incrementingLoader() {
72      return new IncrementingLoader();
73    }
74  
75    /**
76     * Returns a {@link CacheLoader} that throws the given error for every request.
77     */
78    static <K, V> CacheLoader<K, V> errorLoader(final Error e) {
79      checkNotNull(e);
80      return new CacheLoader<K, V>() {
81        @Override
82        public V load(K key) {
83          throw e;
84        }
85      };
86    }
87  
88    /**
89     * Returns a {@link CacheLoader} that throws the given exception for every request.
90     */
91    static <K, V> CacheLoader<K, V> exceptionLoader(final Exception e) {
92      checkNotNull(e);
93      return new CacheLoader<K, V>() {
94        @Override
95        public V load(K key) throws Exception {
96          throw e;
97        }
98      };
99    }
100 
101   /**
102    * Returns a {@link CacheLoader} that returns the key for every request.
103    */
104   static <T> IdentityLoader<T> identityLoader() {
105     return new IdentityLoader<T>();
106   }
107 
108   /**
109    * Returns a {@code new Object()} for every request, and increments a counter for every request.
110    * The count is accessible via {@link #getCount}.
111    */
112   static class CountingLoader extends CacheLoader<Object, Object> {
113     private final AtomicInteger count = new AtomicInteger();
114 
115     @Override
116     public Object load(Object from) {
117       count.incrementAndGet();
118       return new Object();
119     }
120 
121     public int getCount() {
122       return count.get();
123     }
124   }
125 
126   static final class ConstantLoader<K, V> extends CacheLoader<K, V> {
127     private final V constant;
128 
129     ConstantLoader(V constant) {
130       this.constant = constant;
131     }
132 
133     @Override
134     public V load(K key) {
135       return constant;
136     }
137   }
138 
139   /**
140    * Returns a {@code new Object()} for every request, and increments a counter for every request.
141    * An {@code Integer} loader that returns the key for {@code load} requests, and increments the
142    * old value on {@code reload} requests. The load counts are accessible via {@link #getLoadCount}
143    * and {@link #getReloadCount}.
144    */
145   static class IncrementingLoader extends CacheLoader<Integer, Integer> {
146     private final AtomicInteger countLoad = new AtomicInteger();
147     private final AtomicInteger countReload = new AtomicInteger();
148 
149     @Override
150     public Integer load(Integer key) {
151       countLoad.incrementAndGet();
152       return key;
153     }
154 
155     @GwtIncompatible("reload")
156     @Override
157     public ListenableFuture<Integer> reload(Integer key, Integer oldValue) {
158       countReload.incrementAndGet();
159       return Futures.immediateFuture(oldValue + 1);
160     }
161 
162     public int getLoadCount() {
163       return countLoad.get();
164     }
165 
166     public int getReloadCount() {
167       return countReload.get();
168     }
169   }
170 
171   static final class IdentityLoader<T> extends CacheLoader<T, T> {
172     @Override
173     public T load(T key) {
174       return key;
175     }
176   }
177 }